use deadpool_redis::{Connection, Pool};
use std::error::Error;
use std::sync::Arc;
use deadpool_redis::redis::AsyncCommands;
use rocket::State;
use rocket::tokio::sync::Mutex;
use serde::{Deserialize, Serialize};

/// 异步互斥包装的 Redis 连接池类型别名。
type RedisPool = Arc<Mutex<Pool>>;

/// RedisUtil 提供与 Redis 数据库交互的方法。
#[derive(Clone)]
pub struct RedisUtil {
    pool: RedisPool,
}

impl RedisUtil {
    /// 使用给定的 Redis 连接池构造一个新的 RedisUtil 实例。
    pub fn new(pool: &Pool) -> Self {
        RedisUtil {
            pool: Arc::new(Mutex::new(pool.clone())),
        }
    }

    /// 使用给定的 Actix上下文中的 Redis 连接池构造一个新的 RedisUtil 实例。
    pub fn new_by_ctx_pool(pool: &State<Pool>) -> Self {
        let redis_pool = pool.inner();
        RedisUtil {
            pool: Arc::new(Mutex::new(redis_pool.clone())),
        }
    }

    /// 从 Redis 中获取与指定键关联的值。
    ///
    /// 如果键存在则返回 `Some(value)`，否则返回 `None`。
    pub async fn get(&self, key: &str) -> Result<Option<String>, Box<dyn Error>> {
        let mut pool = self.pool.lock().await;
        let mut conn: Connection = pool.get().await?;
        let result: Option<String> = conn.get(key).await?;
        Ok(result)
    }

    /// 设置 Redis 中的键值对。
    ///
    /// 如果键已存在，则覆盖现有值。
    pub async fn set(&self, key: &str, value: &str) -> Result<(), Box<dyn Error>> {
        let mut pool = self.pool.lock().await;
        let mut conn: Connection = pool.get().await?;
        conn.set(key, value).await?;
        Ok(())
    }

    /// 从 Redis 中删除指定的键。
    ///
    /// 如果键删除成功，则返回 `()`。
    pub async fn delete(&self, key: &str) -> Result<(), Box<dyn Error>> {
        let mut pool = self.pool.lock().await;
        let mut conn: Connection = pool.get().await?;
        conn.del(key).await?;
        Ok(())
    }

    /// 设置 Redis 中键的过期时间（以秒为单位）。
    ///
    /// 如果设置成功，则返回 `()`。
    pub async fn expire(&self, key: &str, seconds: usize) -> Result<(), Box<dyn Error>> {
        let mut pool = self.pool.lock().await;
        let mut conn: Connection = pool.get().await?;
        conn.expire(key, seconds).await?;
        Ok(())
    }

    /// 从 Redis 中检索与指定模式匹配的所有键。
    ///
    /// 返回一个字符串向量，表示匹配的键。
    pub async fn keys(&self, pattern: &str) -> Result<Vec<String>, Box<dyn Error>> {
        let mut pool = self.pool.lock().await;
        let mut conn: Connection = pool.get().await?;
        let keys: Vec<String> = conn.keys(pattern).await?;
        Ok(keys)
    }

    /// 将结构化数据（使用 serde 序列化）设置到 Redis 中。
    ///
    /// 在存储之前，将值序列化为 JSON 格式。
    pub async fn set_struct<T>(&self, key: &str, value: &T) -> Result<(), Box<dyn Error>>
    where
        T: Serialize,
    {
        let mut pool = self.pool.lock().await;
        let mut conn: Connection = pool.get().await?;
        let value_str = serde_json::to_string(value)?;
        conn.set(key, value_str).await?;
        Ok(())
    }

    /// 从 Redis 中检索并反序列化结构化数据。
    ///
    /// 将 JSON 值反序列化为指定类型。
    pub async fn get_struct<T>(&self, key: &str) -> Result<Option<T>, Box<dyn Error>>
    where
        T: Deserialize<'static>,
    {
        let pool = self.pool.lock().await;
        let mut conn: Connection = pool.get().await?;
        let value: Option<String> = conn.get(key).await?;
        match value {
            Some(v) => {
                let static_v: &'static str = Box::leak(v.into_boxed_str()) as &'static str;
                let result: T = serde_json::from_str(static_v)?;
                Ok(Some(result))
            }
            None => Ok(None),
        }
    }
}